]> dgit.raspbian.org Git - gnome-shell.git/commitdiff
errorUtils: Add logErrorUnlessCancelled() helper
authorFlorian Müllner <fmuellner@gnome.org>
Wed, 22 Oct 2025 00:59:20 +0000 (02:59 +0200)
committerMarge Bot <marge-bot@gnome.org>
Fri, 24 Oct 2025 15:37:15 +0000 (15:37 +0000)
It is quite common to handle errors by ignoring them in case of
CANCELLED, and otherwise log them via logError().

Add a small helper method that implements that behavior, including
if the original error is wrapped in a Gio.DBusError.

Part-of: <https://gitlab.gnome.org/GNOME/gnome-shell/-/merge_requests/3927>

js/misc/errorUtils.js
tests/meson.build
tests/unit/errorUtils.js [new file with mode: 0644]

index 369a06b02dc6b25a9813efc370dad56befead79c..55e8acf66d1b85ee7df260ada4baea58f18fcdfd 100644 (file)
@@ -1,4 +1,6 @@
 // Common code for displaying errors to the user in various dialogs
+import Gio from 'gi://Gio';
+import GLib from 'gi://GLib';
 
 function formatSyntaxErrorLocation(error) {
     const {fileName = '<unknown>', lineNumber = 0, columnNumber = 0} = error;
@@ -64,3 +66,26 @@ export function formatError(error, {showStack = true} = {}) {
         return `(could not display error: ${e})`;
     }
 }
+
+/**
+ * Logs a stack trace for `error` with an optional prefix, unless the error
+ * matches `Gio.IOErrorEnum.CANCELLED`.
+ *
+ * @param {Error} error - the error to log
+ * @param {string?} prefix - optional prefix for the message
+ *
+ * @returns {boolean} whether the error was logged
+ */
+export function logErrorUnlessCancelled(error, prefix) {
+    if (error instanceof GLib.Error && Gio.DBusError.is_remote_error(error)) {
+        const errorName = Gio.DBusError.get_remote_error(error);
+        Gio.DBusError.strip_remote_error(error);
+        error = Gio.DBusError.new_for_dbus_error(errorName, error.message);
+    }
+
+    if (error.matches(Gio.IOErrorEnum, Gio.IOErrorEnum.CANCELLED))
+        return false;
+
+    logError(error, prefix);
+    return true;
+}
index 806a0c7adc9d5e60f7cecaa7d06b045fee3efbac..ec8a5b4a274ee518092960de705a6d3c299adf5a 100644 (file)
@@ -30,6 +30,7 @@ unit_testenv.append('GI_TYPELIB_PATH', st_typelib_path, separator: ':')
 
 unit_tests = {
   'breakManager': {},
+  'errorUtils': {},
   'extensionUtils': {},
   'fileUtils': {
     'env': {
diff --git a/tests/unit/errorUtils.js b/tests/unit/errorUtils.js
new file mode 100644 (file)
index 0000000..7b79195
--- /dev/null
@@ -0,0 +1,49 @@
+import GLib from 'gi://GLib';
+import Gio from 'gi://Gio';
+
+import {logErrorUnlessCancelled} from 'resource:///org/gnome/shell/misc/errorUtils.js';
+
+describe('logErrorUnlessCancelled()', () => {
+    let spy;
+
+    beforeEach(() => {
+        spy = spyOn(globalThis, 'logError');
+    });
+
+    it('logs regular errors', () => {
+        const e = new Error('Test error');
+        expect(logErrorUnlessCancelled(e)).toBeTrue();
+        expect(spy).toHaveBeenCalled();
+    });
+
+    it('logs GErrors', () => {
+        const e = GLib.Error.new_literal(
+            Gio.IOErrorEnum, Gio.IOErrorEnum.FAILED, 'Failed');
+        expect(logErrorUnlessCancelled(e)).toBeTrue();
+        expect(spy).toHaveBeenCalled();
+    });
+
+    it('does not log CANCELLED errors', () => {
+        const e = GLib.Error.new_literal(
+            Gio.IOErrorEnum, Gio.IOErrorEnum.CANCELLED, 'Cancelled');
+        expect(logErrorUnlessCancelled(e)).toBeFalse();
+        expect(spy).not.toHaveBeenCalled();
+    });
+
+    it('handles remote errors', () => {
+        function createDBusError(code, message) {
+            const e = GLib.Error.new_literal(
+                Gio.IOErrorEnum, code, message);
+            return Gio.DBusError.new_for_dbus_error(
+                Gio.DBusError.encode_gerror(e), message);
+        };
+
+        let e = createDBusError(Gio.IOErrorEnum.CANCELLED, 'Cancelled');
+        expect(logErrorUnlessCancelled(e)).toBeFalse();
+        expect(spy).not.toHaveBeenCalled();
+
+        e = createDBusError(Gio.IOErrorEnum.FAILED, 'Failed');
+        expect(logErrorUnlessCancelled(e)).toBeTrue();
+        expect(spy).toHaveBeenCalled();
+    });
+});